﻿using System;
using System.Collections;
using System.Reflection;
using System.ServiceModel;
using System.ServiceProcess;
using System.Configuration.Install;
using TheGame.Webservices;

namespace TheGame.Server
{
	class WorldService : ServiceBase
	{
		private readonly World _world;
		public ServiceHost ServiceHost;
		public ServiceHost CrossDomainHost;
		public WorldService()
		{
			ServiceName = "TheGame World Server";
			_world = World.Instance;
		}

		public static void Main(string[] args)
		{
			ServiceController controller;
			ServiceControllerStatus controllerStatus;
			WorldService service = new WorldService();
			//Console.BackgroundColor = ConsoleColor.DarkBlue;
			//Console.ForegroundColor = ConsoleColor.White;
			//Console.Clear();
			GetServiceController(service.ServiceName, out controller, out controllerStatus);
			if (args.Length > 0)
			{
				switch(args[0])
				{
					case "-install":
						if(controller == null)
						{
							InstallerTransaction(service.ServiceName, true);
							GetServiceController(service.ServiceName, out controller, out controllerStatus);
							StartService(controller, controllerStatus);
						}
						break;
					case "-uninstall":
						if (controller != null)
						{
							StopService(controller, controllerStatus);
							InstallerTransaction(service.ServiceName, false);
						}
						break;
					default:
						Console.WriteLine("Commandline options:\n-install -- installs the service\n-uninstall -- uninstalls the service");
						break;
				}
				return;
			}
#if DEBUG
			Console.WriteLine("Starting server in console mode...");
			new WorldService().RunConsole();
#else
			ServiceBase.Run(new WorldService());
#endif
		}

		void RunConsole()
		{
			try
			{
				OnStart(null);
				Console.WriteLine("Running...");
				Console.Read();
				OnStop();
			}
			catch(Exception ex)
			{
				Console.WriteLine(ex.Message);
			}
		}

		protected override void OnStart(string[] args)
		{
			if(ServiceHost != null)
				ServiceHost.Close();
			if(CrossDomainHost != null)
				CrossDomainHost.Close();
			try
			{
				Console.WriteLine("Starting world.");
				_world.Startup();
			}
			catch(Exception ex)
			{
				Console.WriteLine("Failed to start world.\n\nError:\n"+ex.Message);
			}
			_world.OnWorldMaintenance += OnWorldMaintenance;
			CrossDomainHost = new ServiceHost(typeof(CrossDomainService));
			Console.WriteLine("Starting cross domain service...");
			CrossDomainHost.Open();

			ServiceHost = new ServiceHost(typeof(TheGameService));
			Console.WriteLine("Starting Admin WCF service...");
			ServiceHost.Open();
		}

		void OnWorldMaintenance()
		{
			//try
			//{
			//    Console.WriteLine("Trying to save database...");
			//    //World.Instance.Database.SaveChanges();
			//    Console.WriteLine("Sucessful.");
			//}
			//catch(Exception ex)
			//{
			//    Console.WriteLine("Error:\n"+ex.Message);
			//}
		}

		protected override void OnStop()
		{
			if(ServiceHost != null)
			{
				ServiceHost.Close();
				ServiceHost = null;
			}
		}

		private static void InstallerTransaction(string serviceName, bool isInstall)
		{
			ServerInstaller installer = new ServerInstaller();
			TransactedInstaller transactedInstaller = new TransactedInstaller();
			transactedInstaller.Installers.Add(installer);
			string str = string.Format("/assemblypath={0}", Assembly.GetEntryAssembly().Location);
			string[] commandLine = isInstall ? new[] { str } : new[] { str, serviceName };
			InstallContext context = new InstallContext(@"S:\TheGameServerInstall.log", commandLine);
			transactedInstaller.Context = context;

			if (isInstall)
				transactedInstaller.Install(new Hashtable());
			else
				transactedInstaller.Uninstall(null);
			Console.WriteLine("Now committing install transaction...");
			transactedInstaller.Commit(new Hashtable());
		}

		private static void StartService(ServiceController controller, ServiceControllerStatus status)
		{
			if (controller != null && status == ServiceControllerStatus.Stopped)
			{
				//_message = "start service";
				controller.Start();
				controller.WaitForStatus(ServiceControllerStatus.Running);
			}
		}

		private static void StopService(ServiceController controller, ServiceControllerStatus status)
		{
			if (controller != null && status == ServiceControllerStatus.Running && controller.CanStop)
			{
				//_message = "stop service";
				controller.Stop();
				controller.WaitForStatus(ServiceControllerStatus.Stopped);
			}
		}

		private static void GetServiceController(string serviceName, out ServiceController controller, out ServiceControllerStatus status)
		{
			try
			{
				controller = new ServiceController(serviceName);
				status = controller.Status;
			}
			catch (InvalidOperationException)
			{
				controller = null;
				status = ServiceControllerStatus.Stopped;
			}
		}
	}
}
